home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 46 / Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso / -serious- / comms / other / amivnc / amivnc.c < prev    next >
C/C++ Source or Header  |  1999-09-06  |  67KB  |  1,556 lines

  1. // AmiVNC - Amiga experimental VNC server - Protocol ORL version 3.3
  2.  
  3. // Includes ***********************************************
  4. // Needed to compile : SDK Cybergraphx 4.1 & SDK AmiTCP 4.3
  5. #include <exec/types.h>
  6. #include <exec/memory.h>
  7. #include <devices/input.h>
  8. #include <devices/inputevent.h>
  9. #include <libraries/commodities.h>
  10. #include <proto/all.h>
  11. #include <proto/socket.h>
  12. #include <dos.h>
  13.  
  14. #ifndef PLANAR
  15. #include <cybergraphx/cybergraphics.h>
  16. #include <proto/cybergraphics.h>
  17. #endif
  18.  
  19. #include <dos/dostags.h>
  20. #include <sys/socket.h>
  21. #include <sys/ioctl.h>
  22. #include <netinet/in.h>
  23. #include <netdb.h>
  24.  
  25. #include <intuition/intuitionbase.h>
  26. #include <intuition/intuition.h>
  27. #include <graphics/displayinfo.h>
  28. #include <graphics/gfxbase.h>
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. #include <fcntl.h>
  35. #include <ctype.h>
  36.  
  37. // Specific Includes ***********************************************
  38. #include "rfbproto.h"                   // Structures & constants for VNC protocol
  39. #include "vncauth.h"                    // Prototypes for authentication
  40.  
  41. // Constants ***********************************************
  42. #define FALSE           0               // What's that ?
  43. #define TRUE            1               // And this ?
  44. #define XDC_PORT        5900            // Port # for bind()
  45. #define XDC_TILE        32              // Tile size
  46. #define XDC_C_VBUF      (1L << 0)       // Bitmask for pBuffer allocation
  47. #define XDC_C_MSOCK     (1L << 1)       // Bitmask for listen socket open
  48. #define XDC_C_CSOCK     (1L << 2)       // Bitmask for client socket open
  49. #define XDC_C_MAXDEPTH  4               // Max. raster depth : 4 bytes / pixel
  50. #define XDC_LOGFILE     "T:AmiVNC.log"  // Log file name
  51. #undef  PARANO
  52.  
  53. // Common messages
  54. char XDC_ID[] = "AmiVNC 0.0.15 Aug 23 1999 (VVA support)";
  55. char XDC_SEND[] = "main.c / main : send() error";
  56. char XDC_RECV[] = "main.c / main : recv() error";
  57.  
  58. // Global variables ***********************************************
  59. LONG    iDuplicateSocketKey;            // Client socket key for transmitting to child process
  60. ULONG   uOpened = NULL;                 // Opened resources, to be closed on exit
  61. BOOL    bDie = FALSE, *pDie = &bDie;    // TRUE : processes are to exit (Argh, very trashy)
  62. BOOL    bSession = FALSE;               // TRUE : clientsession opened
  63. char    cPassword[MAXPWLEN + 1],        // Password
  64.         *pPreStart = NULL,              // User command to execute when connection accepted
  65.         *pPostStop = NULL;              // User command to execute when session closes
  66. LONG    iMasterSocket,                  // Listening socket for incoming connections
  67.         iClientSocket;                  // Client socket accept()ed
  68. UBYTE   *pBuffer = NULL,                // Reference buffer for screen change detection
  69.         *P2CBuffer = NULL;              // Temp buffer for ReadPixelArray8() in planar2chunky
  70. char    *sPWFile = "S:AmiVNC.pwd";      // Password file name
  71. FILE    *fLog = stdout;                 // Logfile
  72. struct  sockaddr_in cliAddr;            // To find client IP address. Must be addressable for getpeername. 
  73. struct  BitMap *pBM = NULL;             // Temp. BitMap for temp. RastPort for p2c
  74.  
  75. // Free all resources allocated to a client session ***********************************************
  76. void vCleanSession(char *cMsg, long lCode)
  77. {
  78.     // Tell the child process to exit (as we are the main process,
  79.     // we can use bDie, which is in our address space)
  80.     if (!bDie)
  81.     {
  82.         bDie = TRUE;
  83.         Delay(125);
  84.     }
  85.     
  86.     // Close everything opened
  87.     if (uOpened & XDC_C_VBUF)   { free(pBuffer); pBuffer = NULL; uOpened ^= XDC_C_VBUF; }
  88.     if (pBM)                    { FreeBitMap(pBM); pBM = NULL; }
  89.     if (P2CBuffer)              { free(P2CBuffer); ; P2CBuffer = NULL; }
  90.     if (uOpened & XDC_C_CSOCK)
  91.     {
  92.         CloseSocket(iClientSocket);
  93.         uOpened ^= XDC_C_CSOCK;
  94.         
  95.         // Execute post-close user command (if any)
  96.         if (bSession && pPostStop)
  97.         {
  98.              char cCommand[128];
  99.              sprintf(cCommand, pPostStop, inet_ntoa(cliAddr.sin_addr));
  100.              SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE);
  101.              bSession = FALSE;
  102.         }
  103.     }
  104.     
  105.     fprintf(fLog, "AmiVNC - %s (%ld)\nAmiVNC session closed\n", cMsg, lCode);
  106. }
  107.  
  108. // Free all resources allocated to main process and exit ***********************************************
  109. void vCleanExit(char *cMsg, long lCode)
  110. {
  111.     // Free tooltype ArgArray initialized by ArgArrayInit()
  112.     // ArgArrayDone();
  113.     
  114.     vCleanSession(cMsg, lCode);
  115.     
  116.     if (uOpened & XDC_C_MSOCK) { CloseSocket(iMasterSocket); uOpened ^= XDC_C_MSOCK; }
  117.     
  118.     fprintf(fLog, "AmiVNC halted\n");
  119.     
  120.     if (fLog != stdout) fclose(fLog);
  121.     
  122.     exit(0L);
  123. }
  124.  
  125. // Handle CTRL-C : do nothing. Will anyways abort blocking socket calls with error, thus provoke exit.
  126. void __regargs _CXBRK(void)
  127. {
  128. }
  129.  
  130. // Authentication ***********************************************
  131. BOOL bAuthentify(void)
  132. {
  133.         char cChallenge[16], cResponse[16];
  134.         CARD32 c32Value;
  135.         BOOL bAuthenticated = TRUE;
  136.         int iCnt, iFile;
  137.  
  138.         // Read encoded password in s:AmiVNC.pwd
  139.         if (!(iFile = open(sPWFile, O_RDONLY, 0)))
  140.            return(FALSE);
  141.                 
  142.         iCnt = read(iFile, cPassword, sizeof(cPassword));
  143.         
  144.         close(iFile);
  145.         
  146.         if (iCnt != sizeof(cPassword))
  147.            return(FALSE);
  148.  
  149.         // Decode password
  150.         vncDecryptPasswd(cPassword, cPassword);
  151.         
  152.         // Authenticate the connection, if required
  153.         if (!strlen(cPassword))
  154.         {
  155.                 // Send no-auth-required message
  156.                 c32Value = rfbNoAuth;
  157.                 if (!(-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0))))
  158.                         return FALSE;
  159.  
  160.                 return(TRUE);
  161.         }
  162.         else
  163.         {
  164.                 // Send auth-required message
  165.                 c32Value = rfbVncAuth;
  166.                 if (-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0)))
  167.                         return FALSE;
  168.  
  169.                 // Now create a 16-byte challenge
  170.                 vncRandomBytes((BYTE *)cChallenge);
  171.  
  172.                 // Send the challenge to the client
  173.                 if (-1 == (send(iClientSocket, cChallenge, sizeof(cChallenge), 0)))
  174.                         return FALSE;
  175.  
  176.                 // Read the response
  177.                 if (-1 == (recv(iClientSocket, cResponse, sizeof(cResponse), 0)))
  178.                         return FALSE;
  179.  
  180.                 // Encrypt the challenge bytes
  181.                 vncEncryptBytes((BYTE *)cChallenge, cPassword);
  182.  
  183.                 // Compare them to the response
  184.                 for (iCnt = 0; iCnt < sizeof(cChallenge); iCnt++)
  185.                 {
  186.                         if (cChallenge[iCnt] != cResponse[iCnt])
  187.                         {
  188.                                 bAuthenticated = FALSE;
  189.                                 break;
  190.                         }
  191.                 }
  192.  
  193.                 // Did the authentication work?
  194.                 if (!bAuthenticated)
  195.                 {
  196.                         c32Value = rfbVncAuthFailed;
  197.                         send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0);
  198.                         return FALSE;
  199.  
  200.                 }
  201.                 else
  202.                 {
  203.                         // Tell the client we're ok
  204.                         c32Value = rfbVncAuthOK;
  205.                         if (-1 == (send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0)))
  206.                                 return FALSE;
  207.                 
  208.                         return(TRUE);
  209.                 }
  210.         }
  211. }
  212.  
  213. // Incoming messages management thread ***********************************************
  214. void __saveds vProcessIncomes(void)
  215. {
  216.     struct IOStdReq *inputReqBlk;
  217.     struct MsgPort *inputPort;
  218.     struct InputEvent eEvent, *VNCEvent = &eEvent;
  219.     UWORD uQualifier = 0;
  220.     rfbClientToServerMsg sCMsg;
  221.     BOOL bLClick = FALSE, bMClick = FALSE, bRClick = FALSE;
  222.     struct Library *SocketBase;
  223.     LONG iSocketChild;
  224.  
  225.     // We have to reopen bsdsocket.library, because it can not be shared between processes
  226.     // OpenLibrary can not fail since it would have halted the father before creating us.
  227.     SocketBase = OpenLibrary("bsdsocket.library", 4L);
  228.  
  229.     // Obtain the client socket descriptor from the key saved for us by our father
  230.     if (-1 == (iSocketChild = ObtainSocket(iDuplicateSocketKey, AF_INET, SOCK_STREAM, 0)))
  231.     {
  232.         fprintf(fLog, "main.c / vProcessIncomes : ObtainSocket() error %d\n", Errno());
  233.         *pDie = TRUE;
  234.         goto _Nosock;
  235.     }
  236.     
  237.     fprintf(fLog, "main.c / vProcessIncomes runs on socket %d\n", iSocketChild);
  238.  
  239.     // Create input.device message structure
  240.     inputPort = CreatePort(NULL, NULL);
  241.     inputReqBlk = (struct IOStdReq *) CreateExtIO(inputPort, sizeof(struct IOStdReq));
  242.     OpenDevice("input.device", NULL, (struct IORequest *) inputReqBlk, NULL);
  243.     inputReqBlk -> io_Data = (APTR) VNCEvent;
  244.     inputReqBlk -> io_Command = IND_WRITEEVENT;
  245.     inputReqBlk -> io_Flags = 0;
  246.     inputReqBlk -> io_Length = sizeof(struct InputEvent);
  247.     
  248.     // Process incoming messages until main process tells to die.
  249.     // Use pointer to bDie because it is not in our address space...
  250.     while (!*pDie) // VERY VERY dirty way to know we have to exit...
  251.     {
  252.        if (-1 == recv(iSocketChild, (UBYTE *) &sCMsg, 1, 0))
  253.        {
  254.            fprintf(fLog, "main.c / vProcessIncomes : recv() error, errno = %d\n", Errno());
  255.            *pDie  = TRUE;
  256.            continue;
  257.        }
  258.        
  259.        Forbid(); // Leave us handle properly our input event
  260.        switch(sCMsg.type)
  261.        {
  262.            case rfbSetPixelFormat : // 0
  263.            if (sz_rfbSetPixelFormatMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetPixelFormatMsg - 1, 0))
  264.            {
  265. #ifdef PARANO
  266.                printf("C -> S : rfbSetPixelFormat lanbpp %d depth %d bigE %d tc %d redM %d redS %d GreM %d GreS %d BluM %d BluS %d\n",
  267.                   sCMsg.spf.format.bitsPerPixel,
  268.                   sCMsg.spf.format.depth,
  269.                   sCMsg.spf.format.bigEndian,
  270.                   sCMsg.spf.format.trueColour,
  271.                   sCMsg.spf.format.redMax,
  272.                   sCMsg.spf.format.redShift,
  273.                   sCMsg.spf.format.greenMax,
  274.                   sCMsg.spf.format.greenShift,
  275.                   sCMsg.spf.format.blueMax,
  276.                   sCMsg.spf.format.blueShift
  277.                   );
  278. #endif // PARANO
  279.                break;
  280.            }
  281.            
  282.            case rfbFixColourMapEntries : // 1
  283.            if (sz_rfbFixColourMapEntriesMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFixColourMapEntriesMsg - 1, 0))
  284.            {
  285. #ifdef PARANO
  286.                printf("C -> S : rfbFixColourMapEntries\n");
  287. #endif // PARANO
  288.                break;
  289.            }
  290.            
  291.            case rfbSetEncodings : // 2
  292.            if (sz_rfbSetEncodingsMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetEncodingsMsg - 1, 0))
  293.            {
  294. #ifdef PARANO
  295.                printf("C -> S : rfbSetEncodings\n");
  296. #endif // PARANO
  297.                break;
  298.            }
  299.            
  300.            case rfbFramebufferUpdateRequest : // 3
  301.            if (sz_rfbFramebufferUpdateRequestMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFramebufferUpdateRequestMsg - 1, 0))
  302.            {
  303. #ifdef PARANO            
  304.                printf("C -> S : rfbFramebufferUpdateRequest inc %d x %d y %d w %d h %d\n",
  305.                   sCMsg.fur.incremental,
  306.                   sCMsg.fur.x,
  307.                   sCMsg.fur.y,
  308.                   sCMsg.fur.w,
  309.                   sCMsg.fur.h
  310.                   );
  311. #endif // PARANO            
  312.                break;
  313.            }
  314.            
  315.            case rfbKeyEvent : // 4
  316.            if (sz_rfbKeyEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbKeyEventMsg - 1, 0))
  317.            {
  318. #ifdef PARANO
  319.                printf("C -> S : rfbKeyEvent down %d key %d ('%c')\n",
  320.                   sCMsg.ke.down,
  321.                   sCMsg.ke.key,
  322.                   sCMsg.ke.key
  323.                  );
  324. #endif // PARANO
  325.                // Process special keys
  326.                if ((sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  327.                {
  328.                    if (sCMsg.ke.key == 0xFFE1) uQualifier |= IEQUALIFIER_LSHIFT;  // Left Shift
  329.                    if (sCMsg.ke.key == 0xFFE2) uQualifier |= IEQUALIFIER_RSHIFT;  // Right Shift
  330.                    if (sCMsg.ke.key == 0xFFE3) uQualifier |= IEQUALIFIER_CONTROL; // Left Control
  331.                    if (sCMsg.ke.key == 0xFFE4) uQualifier |= IEQUALIFIER_CONTROL; // Right Control
  332.                    if (sCMsg.ke.key == 0xFFE9) uQualifier |= IEQUALIFIER_LALT;    // Left Alt
  333.                    if (sCMsg.ke.key == 0xFFEA) uQualifier |= IEQUALIFIER_RALT;    // Right Alt
  334.                    break;
  335.                }
  336.                if ((!sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  337.                {
  338.                    if (sCMsg.ke.key == 0xFFE1) uQualifier &= ~IEQUALIFIER_LSHIFT; // Left Shift
  339.                    if (sCMsg.ke.key == 0xFFE2) uQualifier &= ~IEQUALIFIER_RSHIFT; // Right Shift
  340.                    if (sCMsg.ke.key == 0xFFE3) uQualifier &= ~IEQUALIFIER_CONTROL; // Left Control
  341.                    if (sCMsg.ke.key == 0xFFE4) uQualifier &= ~IEQUALIFIER_CONTROL; // Right Control
  342.                    if (sCMsg.ke.key == 0xFFE9) uQualifier &= ~IEQUALIFIER_LALT;    // Left Alt
  343.                    if (sCMsg.ke.key == 0xFFEA) uQualifier &= ~IEQUALIFIER_RALT;    // Right Alt
  344.                    break;
  345.                }
  346.  
  347.                // Do nothing on key release
  348.                if (!sCMsg.ke.down) break;
  349.  
  350.                // Process cursor-related keys
  351.                if (0xFF50 == (sCMsg.ke.key & 0xFF50))
  352.                {
  353.                    VNCEvent -> ie_Class = IECLASS_RAWKEY;
  354.                    VNCEvent -> ie_Qualifier = 0;
  355.                    switch(sCMsg.ke.key & 0x000F)
  356.                    {
  357.                        case 0 : // Home
  358.                            VNCEvent -> ie_Code = 0x3D;
  359.                            break;
  360.                        case 1 : // Left
  361.                            VNCEvent -> ie_Code = 0x4F;
  362.                            break;
  363.                        case 2 : // Up
  364.                            VNCEvent -> ie_Code = 0x4C;
  365.                            break;
  366.                        case 3 : // Right
  367.                            VNCEvent -> ie_Code = 0x4E;
  368.                            break;
  369.                        case 4 : // Down
  370.                            VNCEvent -> ie_Code = 0x4D;
  371.                            break;
  372.                        case 5 : // Page up
  373.                            VNCEvent -> ie_Code = 0x3F;
  374.                            break;
  375.                        case 6 : // Page down
  376.                            VNCEvent -> ie_Code = 0x1F;
  377.                            break;
  378.                        case 7 : // End
  379.                            VNCEvent -> ie_Code = 0x1D;
  380.                            break;
  381.                        default :
  382.                            break;
  383.                    }
  384.                }
  385.                else
  386.                {
  387.                    // Map out other 0xFF'ed keys
  388.                    sCMsg.ke.key &= 0xFF;
  389.                    
  390.                    // Find rawkey event out of key ; if we can not, reject key
  391.                    if (!InvertKeyMap((ULONG) sCMsg.ke.key, VNCEvent, NULL))
  392.                    break;
  393.                }
  394.                
  395.                // Apply qualifier if possible
  396.                if (!strchr("~`£µ¨89", (int) sCMsg.ke.key)) switch(uQualifier)
  397.                {
  398.                    case IEQUALIFIER_CONTROL :
  399.                    case IEQUALIFIER_LSHIFT :
  400.                    case IEQUALIFIER_RSHIFT :
  401.                        VNCEvent -> ie_Qualifier = uQualifier;
  402.                        break;
  403.                            
  404.                    case IEQUALIFIER_LALT :
  405.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_LCOMMAND;
  406.                        break;
  407.                            
  408.                    case IEQUALIFIER_RALT | IEQUALIFIER_CONTROL :
  409.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_RCOMMAND;
  410.                        break;
  411.                }
  412.                
  413.                // Send key into input.device
  414.                DoIO((struct IORequest *) inputReqBlk);
  415.            break;
  416.            }
  417.            
  418.            case rfbPointerEvent : // 5
  419.            if (sz_rfbPointerEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbPointerEventMsg - 1, 0))
  420.            {
  421. #ifdef PARANO
  422.                printf("C -> S : rfbPointerEvent button %d x %d y %d\r",
  423.                   sCMsg.pe.buttonMask,
  424.                   sCMsg.pe.x,
  425.                   sCMsg.pe.y
  426.                  );
  427. #endif // PARANO
  428.                VNCEvent -> ie_NextEvent = NULL;
  429.                VNCEvent -> ie_Class = IECLASS_POINTERPOS;
  430.                VNCEvent -> ie_Qualifier = uQualifier;
  431.                
  432.                // Process mouse X & Y
  433.                VNCEvent -> ie_X = sCMsg.pe.x;
  434.                VNCEvent -> ie_Y = sCMsg.pe.y;
  435.  
  436.                // Process mouse buttons...
  437.                VNCEvent -> ie_Code = IECODE_NOBUTTON;
  438.                
  439.                // Left button
  440.                if ((sCMsg.pe.buttonMask) & 1)
  441.                {
  442.                    if (bLClick)
  443.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  444.                    else
  445.                    {
  446.                         bLClick = TRUE; VNCEvent -> ie_Code = IECODE_LBUTTON; uQualifier |= IEQUALIFIER_LEFTBUTTON;
  447.                    }
  448.                }
  449.                else if (bLClick) { bLClick = FALSE; VNCEvent -> ie_Code = IECODE_LBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_LEFTBUTTON; }
  450.  
  451.                // Middle button
  452.                if ((sCMsg.pe.buttonMask) & 2)
  453.                {
  454.                    if (bMClick)
  455.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  456.                    else
  457.                    {
  458.                         bMClick = TRUE; VNCEvent -> ie_Code = IECODE_MBUTTON;  uQualifier |= IEQUALIFIER_MIDBUTTON;
  459.                    }
  460.                }
  461.                else if (bMClick) { bMClick = FALSE; VNCEvent -> ie_Code = IECODE_MBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_MIDBUTTON; }
  462.  
  463.                // Right button
  464.                if ((sCMsg.pe.buttonMask) & 4)
  465.                {
  466.                    if (bRClick)
  467.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  468.                    else
  469.                    {
  470.                         bRClick = TRUE; VNCEvent -> ie_Code = IECODE_RBUTTON;  uQualifier |= IEQUALIFIER_RBUTTON;
  471.                    }
  472.                }
  473.                else if (bRClick) { bRClick = FALSE; VNCEvent -> ie_Code = IECODE_RBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_RBUTTON; }
  474.  
  475.                // Insert event into input.device stream
  476.                DoIO((struct IORequest *) inputReqBlk);
  477.                break;
  478.            }
  479.            
  480.            case rfbClientCutText : // 6
  481.            if (sz_rfbClientCutTextMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbClientCutTextMsg - 1, 0))
  482.            {
  483.                char *cText = malloc((size_t) (sCMsg.cct.length + 1));
  484.                recv(iSocketChild, cText, sCMsg.cct.length, 0);
  485.                cText[sCMsg.cct.length] = 0;
  486. #ifdef PARANO
  487.                printf("C -> S : rfbClientCutText '%s'\n", cText);
  488. #endif // PARANO
  489.                break;
  490.            }
  491.            
  492.            default :
  493. #ifdef PARANO
  494.            printf("main.c / vProcessIncomes : msg type %d unknown\n", sCMsg.type);
  495. #endif // PARANO
  496.            break;
  497.        }
  498.        Permit();
  499.     }
  500.     
  501.     CloseSocket(iSocketChild);
  502.  
  503.     if (inputReqBlk)
  504.     {
  505.         CloseDevice((struct IORequest *) inputReqBlk);
  506.         DeleteExtIO((struct IORequest *) inputReqBlk);
  507.     }
  508.     
  509.     if (inputPort) DeletePort(inputPort);
  510.  
  511. _Nosock:
  512.     CloseLibrary(SocketBase);
  513.     fprintf(fLog, "main.c / vProcessIncomes halted\n");   
  514. }
  515.  
  516. // Main entry point  ***********************************************
  517. int main(int argc, char **argv)
  518. {
  519.     register int iCnt, jCnt;
  520.     BPTR pFile;
  521.     int iMajor, iMinor, iWidth, iHeight, iDepth, iSize, iMode, iPort, iUpdate = 0, iRShift = 8, iGShift = 16, iBShift = 24;
  522.     unsigned long uLimit = 0xFFFFFFFF, uSize, uCnt;
  523.     struct sockaddr_in sAddr;                  // Local address for bind()
  524.     struct Screen *pActiveScreen;
  525.     rfbProtocolVersionMsg mProtVerMsg;
  526.     rfbServerInitMsg mSerInitMsg;
  527.     rfbFramebufferUpdateMsg mFBUpdMsg;
  528.     rfbFramebufferUpdateRectHeader mFBRMsg;
  529.     CARD8 c8;
  530.     BOOL bBig = FALSE, bFastMode, bPlanar, bVVA = FALSE;
  531.     register UBYTE *pRaster;                                    // True WB screen raster
  532.     static UBYTE uTile[XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH];   // 3 Byte/pixel RGB Raster tile for client screen updates
  533.     static UBYTE uCTile[XDC_TILE * XDC_TILE];                   // Chunky tile for planar comparisons 
  534.     char cLog[80], *pC, **ArgArray;
  535.     UWORD  CLUT[256];                                           // 16 bit Planar2Chunky color lookup table (pen number -> RGB16PC values)
  536.     UBYTE  CLUT8[256];                                          // 8 bit Planar2Chunky color lookup table (pen number -> BGR233 values)
  537.     struct RastPort TempRP;                                     // Temp. RastPort for ReadPixelArray8
  538.  
  539. #ifndef PLANAR
  540.     struct Library *CGXlib = OpenLibrary("cgxsystem.library", 40L);
  541. #endif
  542.  
  543.     iPort = XDC_PORT;
  544.     
  545.     strcpy(cLog, XDC_LOGFILE);
  546.     
  547.     // Process AmiVNC icon tooltypes
  548.     ArgArray = ArgArrayInit((long) argc, argv);
  549.     if (pC = FindToolType(ArgArray, "PORT"))      iPort = atoi(pC);
  550.     if (pC = FindToolType(ArgArray, "BIGENDIAN")) bBig = (tolower(*pC) == 't') ? TRUE : FALSE;
  551.     if ((pC = FindToolType(ArgArray, "LIMIT")) && (atoi(pC))) uLimit = atoi(pC);
  552.     if (pC = FindToolType(ArgArray, "RSHIFT"))    iRShift = atoi(pC);
  553.     if (pC = FindToolType(ArgArray, "GSHIFT"))    iGShift = atoi(pC);
  554.     if (pC = FindToolType(ArgArray, "BSHIFT"))    iBShift = atoi(pC);
  555.     if (pC = FindToolType(ArgArray, "LOGFILE"))   strcpy(cLog, pC);
  556.     if (pC = FindToolType(ArgArray, "PRESTART"))  pPreStart = pC;
  557.     if (pC = FindToolType(ArgArray, "POSTSTOP"))  pPostStop = pC;
  558.     if (pC = FindToolType(ArgArray, "VERBOSE"))   cLog[0] = 0;
  559.     if (pC = FindToolType(ArgArray, "VVA"))       bVVA = TRUE;
  560.     
  561.     // Process command line arguments (if any)
  562.     if (argc > 1) while (*++argv)
  563.     {
  564.         switch(tolower((*argv)[1]))
  565.         {
  566.             // *** Print usage
  567.             case '?' :
  568.             case 'h' :
  569.                 printf("Options :\n -p<pwd> to store password\n");
  570.                 printf(" -s<port> to set listen port (default %d)\n", XDC_PORT);
  571.                 printf(" -e to force big endian (default little)\n");
  572.                 printf(" -l<size> to limit net block size (default unlimited\n");
  573.                 printf(" -(r|g|b)<value> to force color encoding r|g|b bitshift (defaults 8|16|24)\n");
  574.                 vCleanExit("main.c / main : stopping...", 0);
  575.                 break;
  576.                 
  577.             // *** Force password change and exit
  578.             case 'p' :
  579.                 strncpy(cPassword, *argv + 2, MAXPWLEN);
  580.                 cPassword[MAXPWLEN] = '\0';
  581.                 
  582.                 pC = strchr(cPassword, ' ');
  583.                 if (pC) *pC = '\0';
  584.                 
  585.                 for (iCnt = strlen(cPassword) ; iCnt < MAXPWLEN ; iCnt++)
  586.                    cPassword[iCnt] = '\0';
  587.                 
  588.                 vncEncryptPasswd(cPassword, cPassword);
  589.                 
  590.                 if (!(pFile = Open(sPWFile, MODE_NEWFILE)))
  591.                     vCleanExit("main.c / main : creat('s:AmiVNC.pwd') error", 0);
  592.                 Write(pFile, cPassword, sizeof(cPassword));
  593.                 Close(pFile);
  594.                 
  595.                 vCleanExit("main.c / main : Passwd stored", 0);
  596.                 break;
  597.             
  598.             // *** Force another port than the default 5900
  599.             case 's' :
  600.                 iPort = atoi(*argv + 2);
  601.                 break;
  602.             
  603.             // *** Force BigEndian flag in mSerInitMsg
  604.             case 'e' :
  605.                 bBig = TRUE;
  606.                 break;
  607.             
  608.             // *** Limit netblocksize for initial screen update
  609.             case 'l' :
  610.                 uLimit = atoi(*argv + 2);
  611.                 break;
  612.                 
  613.             // *** Force Red / Green / Blue bitshifts in mSerInitMsg
  614.             // (play with this if you have color problems, legal values
  615.             // for shifts are 0, 8, 16 and 24)
  616.             case 'r' :
  617.                 iRShift = atoi(*argv + 2);
  618.                 break;
  619.                 
  620.             case 'g' :
  621.                 iGShift = atoi(*argv + 2);
  622.                 break;
  623.                 
  624.             case 'b' :
  625.                 iBShift = atoi(*argv + 2);
  626.                 break;
  627.                 
  628.             // Force verbose mode to sdtout
  629.             case 'v' :
  630.                 cLog[0] = 0;
  631.                 break;
  632.                 
  633.             // Force VVA compatible (BGR233) pixel encoding
  634.             case 'a' :
  635.                 bVVA = TRUE;
  636.                 break;
  637.                 
  638.             default :
  639.                 printf("main.c / main : Arg [%s] ignored\n", *argv);
  640.                 break;
  641.         }
  642.     }
  643.     
  644.     // If log not forced to stdout, open log file
  645.     if (cLog[0])
  646.     {
  647.         fLog = fopen(cLog, "wt");
  648.         if (!fLog)
  649.         {
  650.             fLog = stdout;
  651.             vCleanExit("main.c / main : Log file error", 0);
  652.         }
  653.     }
  654.  
  655.     // Welcome...
  656.     fprintf(fLog, "%s\n(c) 1999 stephane.guillard@steria.fr\n", XDC_ID);
  657.     
  658.     // Print configurable parameter values
  659.     fprintf(fLog, "main.c / main : parameter values :\n");
  660.     fprintf(fLog, " - listen port set to %d\n", iPort);
  661.     fprintf(fLog, " - endian set to %s\n", bBig ? "big" : "little");
  662.     fprintf(fLog, " - initial xfer limit set to %08lX\n", uLimit);
  663.     fprintf(fLog, " - color bitshifts : red %d, green %d, blue %d\n", iRShift, iGShift, iBShift);
  664.     
  665.     // Prepare listener socket
  666.     fprintf(fLog, "main.c / main : Creating listener socket\n");
  667.     if (-1 == (iMasterSocket = socket(AF_INET, SOCK_STREAM, 0)))
  668.         vCleanExit("main.c / main : socket() error", Errno());
  669.     
  670.     uOpened |= XDC_C_MSOCK;
  671.     
  672.     sAddr.sin_family=AF_INET;
  673.     sAddr.sin_addr.s_addr = 0;
  674.     sAddr.sin_port = htons(iPort);
  675.     
  676.     fprintf(fLog, "main.c / main : Binding socket on port %d\n", sAddr.sin_port);
  677.     if (-1 == (bind(iMasterSocket, (struct sockaddr *) &sAddr, sizeof(sAddr))))
  678.         vCleanExit("main.c / main : bind() error", Errno());
  679.     
  680.     fprintf(fLog, "main.c / main : Listening set on port %d\n", sAddr.sin_port);
  681.     if (-1 == (listen(iMasterSocket, 4)))
  682.         vCleanExit("main.c / main : listen() error", Errno()); 
  683.  
  684. _NewSession:
  685.  
  686.     bDie = FALSE;
  687.     
  688.     // Wait for incoming connections
  689.     fprintf(fLog, "main.c / main : Waiting for client connection\n");
  690.     if (-1 == (iClientSocket = accept(iMasterSocket, NULL, NULL)))
  691.         vCleanExit("main.c / main : accept() error", Errno());
  692.     
  693.     uOpened |= XDC_C_CSOCK;
  694.     
  695.     // Find client IP address (use iDuplicateSocketKey as temp. var because at this point it is useless)
  696.     iDuplicateSocketKey = sizeof(cliAddr);
  697.     getpeername(iClientSocket, (struct sockaddr *) &cliAddr, &iDuplicateSocketKey);
  698.  
  699.     fprintf(fLog, "main.c / main : accept()ed connection from %s on socket %d\n", inet_ntoa(cliAddr.sin_addr), iClientSocket);
  700.     
  701.     // NegociateProtocolVersion
  702.     fprintf(fLog, "main.c / main : Negociating protocol version\n");
  703.     sprintf((char *) mProtVerMsg, rfbProtocolVersionFormat,
  704.     rfbProtocolMajorVersion,
  705.     rfbProtocolMinorVersion);
  706.     if (-1 == (send(iClientSocket, (UBYTE *) mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  707.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  708.     
  709.     mProtVerMsg[12] = 0;
  710.  
  711.     if (-1 == (recv(iClientSocket, mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  712.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  713.  
  714.     sscanf((char *) mProtVerMsg, rfbProtocolVersionFormat, &iMajor, &iMinor);
  715.     fprintf(fLog, "main.c / main : Protocol supported by server : %d.%d, by client : %d.%d\n", rfbProtocolMajorVersion, rfbProtocolMinorVersion, iMajor, iMinor);
  716.  
  717.     // If major == minor == 0, fake client asks us to exit
  718.     if ((!iMajor) && (!iMinor))
  719.         vCleanExit("main.c / main : Exit asked", 0);
  720.         
  721.     // Check protocol version
  722.     if (iMajor > rfbProtocolMajorVersion)
  723.     { vCleanSession("main.c / main : unknown protocol", 0); goto _NewSession; }
  724.     
  725.     // Authenticate DES
  726.     fprintf(fLog, "main.c / main : Authentication\n");
  727.     if (FALSE == bAuthentify())
  728.     { vCleanSession("main.c / main : Authenticate error", 0); goto _NewSession; }
  729.     
  730.     // ClientInit
  731.     fprintf(fLog, "main.c / main : ClientInitialisation\n");
  732.     if (-1 == (recv(iClientSocket, &c8, sizeof(c8), 0)))
  733.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  734.     
  735.     fprintf(fLog, "main.c / main : SharedFlag = %d (multiple clients : %s)\n", c8, c8 ? "Yes" : "No");
  736.  
  737.     // Grab active screen
  738.     pActiveScreen = IntuitionBase -> FirstScreen;
  739.  
  740.     // Check if planar Amiga screen
  741.     bPlanar = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD ? TRUE : FALSE;
  742.  
  743.     fprintf(fLog, "main.c / main : Screen set to [%s] (%s)\n", pActiveScreen -> Title, bPlanar ? "planar" : "RTG");
  744.  
  745.     // Get screen info (mode, width, height, depth, linear address)
  746.     if (!bPlanar) // RTG chunky linear modes
  747.     {
  748. #ifndef PLANAR
  749.         if (GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  750.          && GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM))
  751.         {
  752.             // Get screenmode, width, height, depth
  753.             iMode = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_PIXFMT);
  754.             iWidth = GetCyberMapAttr(pActiveScreen ->  RastPort.BitMap, CYBRMATTR_WIDTH); // X size
  755.             iHeight = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT); // Y size
  756.             iDepth = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_BPPIX); // Depth is in Bytes / pixel
  757.  
  758.             // Grab chunky raster pointer (dirty but EFFICIENT !)
  759.             UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  760.                      LBMI_BASEADDRESS, (ULONG *) &uCnt,
  761.                      TAG_DONE));
  762.             pRaster = (UBYTE *) uCnt;
  763.  
  764.             // Calculate total byte size of screen raster (adjust to 2 byte / pixel if CLUT, will realloc later)
  765.             iSize = iWidth * iHeight * (iDepth > 1 ? iDepth : 2);
  766.             
  767.             fprintf(fLog, "main.c / main : RTG mode %s/%ld ", CGXlib ? "CGFx" : "Pic96", iMode);
  768.         }
  769.         else // mode unsupported (neither planar neither RTG chunky linear)
  770. #endif
  771.         { vCleanSession("main.c / main : screenmode not supported", 0); goto _NewSession; }
  772.     }
  773.     else // non-RTG (Amiga Classic chipset planar modes)
  774.     {
  775.         // Get width, height, depth
  776.         iMode = 0xFF; // To remember this is a non-RTG screen to set up frame buffer format for ServerInit
  777.         iWidth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_WIDTH); // X size
  778.         iHeight = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_HEIGHT); // Y size
  779.         iDepth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel
  780.         
  781.         // Force size to 2 X Y (each planar pixel will be sent as a 2 byte RGB4 chunky pixel)
  782.         iSize = iWidth * iHeight * 2; 
  783.         
  784.         // Screen memory is not linear addressable (but we rather have a raster per bitplane)
  785.         pRaster = NULL;
  786.         
  787.         fprintf(fLog, "main.c / main : planar mode ");
  788.     }
  789.  
  790.     fprintf(fLog, "@ 0x%08lX, %dx%d, %d %cpp, size %d\n", pRaster, iWidth, iHeight, iDepth, bPlanar ? 'b' : 'B', bPlanar ? iWidth * iHeight * iDepth / 8 : iSize);    
  791.  
  792.     // Fast mode : 2 byte pixel buffer :
  793.     // - planar Amiga screens
  794.     //   OR
  795.     // - Picasso96 AND 2 byte pixels
  796.     //   OR
  797.     // - 1 byte RTG CLUT pixels
  798. #ifndef PLANAR
  799.     bFastMode = ((bPlanar) || ((!CGXlib) && (iDepth == 2)) || (iDepth == 1));
  800. #else
  801.     bFastMode = TRUE;
  802. #endif
  803.     // Allocate pBuffer (reference buffer for screen compare)
  804.     // - with the screen size if no VVA, and ((under P96 and Depth < 3) OR if planar)
  805.     // - with 4 byte / pixel size if under CGFx or Depth >= 3 or VVA
  806.     if (!(pBuffer = malloc((!bVVA && bFastMode) ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH)))
  807.     { vCleanSession("main.c / main : malloc() error", 0); goto _NewSession; }
  808.    
  809.     uOpened |= XDC_C_VBUF;
  810.  
  811.     // ServerInit : prepare RGB encodings
  812.     if (bFastMode)
  813.     {
  814. #ifndef PLANAR
  815.         switch(iMode)
  816.         {
  817.             case PIXFMT_RGB16PC : // TESTED OK /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggbbbbbrrrrrggg */
  818.                 mSerInitMsg.format.bitsPerPixel = 16;
  819.                 mSerInitMsg.format.depth = 16;
  820.                 mSerInitMsg.format.bigEndian = TRUE;
  821.                 mSerInitMsg.format.trueColour = TRUE;
  822.                 mSerInitMsg.format.redMax = 31;
  823.                 mSerInitMsg.format.greenMax = 63;
  824.                 mSerInitMsg.format.blueMax = 31;
  825.                 mSerInitMsg.format.redShift = 11;
  826.                 mSerInitMsg.format.greenShift = 5;
  827.                 mSerInitMsg.format.blueShift = 0;
  828.                 break;
  829.             case PIXFMT_RGB15PC :        /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */
  830.                 mSerInitMsg.format.bitsPerPixel = 16;
  831.                 mSerInitMsg.format.depth = 15;
  832.                 mSerInitMsg.format.bigEndian = TRUE;
  833.                 mSerInitMsg.format.trueColour = TRUE;
  834.                 mSerInitMsg.format.redMax = 31;
  835.                 mSerInitMsg.format.greenMax = 31;
  836.                 mSerInitMsg.format.blueMax = 31;
  837.                 mSerInitMsg.format.redShift = 10;
  838.                 mSerInitMsg.format.greenShift = 5;
  839.                 mSerInitMsg.format.blueShift = 0;
  840.                 break;
  841.             case PIXFMT_RGB16 :          /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: rrrrrggggggbbbbb */
  842.                 mSerInitMsg.format.bitsPerPixel = 16;
  843.                 mSerInitMsg.format.depth = 16;
  844.                 mSerInitMsg.format.bigEndian = FALSE;
  845.                 mSerInitMsg.format.trueColour = TRUE;
  846.                 mSerInitMsg.format.redMax = 31;
  847.                 mSerInitMsg.format.greenMax = 63;
  848.                 mSerInitMsg.format.blueMax = 31;
  849.                 mSerInitMsg.format.redShift = 11;
  850.                 mSerInitMsg.format.greenShift = 5;
  851.                 mSerInitMsg.format.blueShift = 0;
  852.                 break;
  853.             case PIXFMT_RGB15 :          /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */
  854.                 mSerInitMsg.format.bitsPerPixel = 16;
  855.                 mSerInitMsg.format.depth = 15;
  856.                 mSerInitMsg.format.bigEndian = FALSE;
  857.                 mSerInitMsg.format.trueColour = TRUE;
  858.                 mSerInitMsg.format.redMax = 31;
  859.                 mSerInitMsg.format.greenMax = 31;
  860.                 mSerInitMsg.format.blueMax = 31;
  861.                 mSerInitMsg.format.redShift = 10;
  862.                 mSerInitMsg.format.greenShift = 5;
  863.                 mSerInitMsg.format.blueShift = 0;
  864.                 break;
  865.             case PIXFMT_BGR16PC :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggrrrrrbbbbbggg */
  866.                 mSerInitMsg.format.bitsPerPixel = 16;
  867.                 mSerInitMsg.format.depth = 16;
  868.                 mSerInitMsg.format.bigEndian = TRUE;
  869.                 mSerInitMsg.format.trueColour = TRUE;
  870.                 mSerInitMsg.format.redMax = 31;
  871.                 mSerInitMsg.format.greenMax = 63;
  872.                 mSerInitMsg.format.blueMax = 31;
  873.                 mSerInitMsg.format.redShift = 0;
  874.                 mSerInitMsg.format.greenShift = 5;
  875.                 mSerInitMsg.format.blueShift = 11;
  876.                 break;
  877.             case PIXFMT_BGR15PC :        /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
  878.                 mSerInitMsg.format.bitsPerPixel = 16;
  879.                 mSerInitMsg.format.depth = 15;
  880.                 mSerInitMsg.format.bigEndian = TRUE;
  881.                 mSerInitMsg.format.trueColour = TRUE;
  882.                 mSerInitMsg.format.redMax = 31;
  883.                 mSerInitMsg.format.greenMax = 31;
  884.                 mSerInitMsg.format.blueMax = 31;
  885.                 mSerInitMsg.format.redShift = 0;
  886.                 mSerInitMsg.format.greenShift = 5;
  887.                 mSerInitMsg.format.blueShift = 10;
  888.                 break;
  889.             case PIXFMT_BGR16 :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: bbbbbggggggrrrrr */
  890.                 mSerInitMsg.format.bitsPerPixel = 16;
  891.                 mSerInitMsg.format.depth = 16;
  892.                 mSerInitMsg.format.bigEndian = FALSE;
  893.                 mSerInitMsg.format.trueColour = TRUE;
  894.                 mSerInitMsg.format.redMax = 31;
  895.                 mSerInitMsg.format.greenMax = 63;
  896.                 mSerInitMsg.format.blueMax = 31;
  897.                 mSerInitMsg.format.redShift = 0;
  898.                 mSerInitMsg.format.greenShift = 5;
  899.                 mSerInitMsg.format.blueShift = 11;
  900.                 break;
  901.             case PIXFMT_BGR15 :        /* HiColor15 (5 bit each), format: 0bbbbbbgggggrrrrr */
  902.                 mSerInitMsg.format.bitsPerPixel = 16;
  903.                 mSerInitMsg.format.depth = 15;
  904.                 mSerInitMsg.format.bigEndian = FALSE;
  905.                 mSerInitMsg.format.trueColour = TRUE;
  906.                 mSerInitMsg.format.redMax = 31;
  907.                 mSerInitMsg.format.greenMax = 31;
  908.                 mSerInitMsg.format.blueMax = 31;
  909.                 mSerInitMsg.format.redShift = 0;
  910.                 mSerInitMsg.format.greenShift = 5;
  911.                 mSerInitMsg.format.blueShift = 10;
  912.                 break;
  913.             
  914.             case PIXFMT_LUT8 :          /* Chunky CLUT screens, or ... */
  915.             case 0xFF :                 /* planar screens : send 2 byte pixels,aligned as per GetRGB4 : 0000RRRR GGGGBBBB*/
  916. #endif
  917.                 mSerInitMsg.format.bitsPerPixel = 16;
  918.                 mSerInitMsg.format.depth = 12;
  919.                 mSerInitMsg.format.bigEndian = FALSE;
  920.                 mSerInitMsg.format.trueColour = TRUE;
  921.                 mSerInitMsg.format.redMax = 15;
  922.                 mSerInitMsg.format.greenMax = 15;
  923.                 mSerInitMsg.format.blueMax = 15;
  924.                 mSerInitMsg.format.redShift = 8; // 0
  925.                 mSerInitMsg.format.greenShift = 4; // 12
  926.                 mSerInitMsg.format.blueShift = 0; // 8
  927. #ifndef PLANAR
  928.                 break;
  929.                 
  930.             default :
  931.                 { vCleanSession("main.c / main : RGB mode not supported", 0); goto _NewSession; }
  932.                 break;
  933.          }
  934.     }
  935.     else // CGFx or Depth > 2 or screen not planar
  936.          // then use dumb 24 bpp mode, sent as 32 bpp because VNC protocol forbids 3 byte pixels
  937.     {
  938.         mSerInitMsg.format.bitsPerPixel = 32;
  939.         mSerInitMsg.format.depth = 24;
  940.         mSerInitMsg.format.bigEndian = bBig;
  941.         mSerInitMsg.format.trueColour = TRUE;
  942.         mSerInitMsg.format.redMax =
  943.         mSerInitMsg.format.greenMax =
  944.         mSerInitMsg.format.blueMax = 255;
  945.         mSerInitMsg.format.redShift = iRShift;
  946.         mSerInitMsg.format.greenShift = iGShift;
  947.         mSerInitMsg.format.blueShift = iBShift;
  948. #endif
  949.     }
  950.  
  951.     
  952.     // if client is VVA, force encoding as BGR233 in all cases, as VVA only knows this encoding
  953.     if (bVVA)
  954.     {
  955.         mSerInitMsg.format.bitsPerPixel = 8;
  956.         mSerInitMsg.format.depth = 8;
  957.         mSerInitMsg.format.bigEndian = FALSE;
  958.         mSerInitMsg.format.trueColour = TRUE;
  959.         mSerInitMsg.format.redMax = 7;
  960.         mSerInitMsg.format.greenMax = 7;
  961.         mSerInitMsg.format.blueMax = 3;
  962.         mSerInitMsg.format.redShift = 0;
  963.         mSerInitMsg.format.greenShift = 3;
  964.         mSerInitMsg.format.blueShift = 6;
  965.     }
  966.     
  967.     // Finish serverinit and send it
  968.     mSerInitMsg.framebufferWidth = iWidth;
  969.     mSerInitMsg.framebufferHeight = iHeight;
  970.     mSerInitMsg.nameLength = sizeof(XDC_ID);
  971.  
  972.     if (-1 == (send(iClientSocket, (UBYTE *) &mSerInitMsg, sizeof(mSerInitMsg), 0)))
  973.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }    
  974.  
  975.     if (-1 == (send(iClientSocket, (UBYTE *) XDC_ID, sizeof(XDC_ID), 0)))
  976.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  977.  
  978.     // Initial Screen update : header...
  979.     mFBUpdMsg.type = rfbFramebufferUpdate;
  980.     mFBUpdMsg.nRects = 1;
  981.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  982.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  983.     
  984.     // Initial Screen update : 1 rectangle for whole screen...
  985.     mFBRMsg.r.x = 0;
  986.     mFBRMsg.r.y = 0;
  987.     mFBRMsg.r.w = iWidth;
  988.     mFBRMsg.r.h = iHeight;
  989.     mFBRMsg.encoding = rfbEncodingRaw;
  990.  
  991.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  992.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  993.  
  994.     // Copy raster into buffer for send() and for ulterior compares
  995.     if ((bFastMode) && (!bVVA)) // Planar or Pic96/2 byte pixels, no VVA
  996.     {
  997.         if (bPlanar)   // planar screen
  998.         {
  999.             // We have to :
  1000.             // - ReadPixelArray8 the whole screen,
  1001.             // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap
  1002.             // - Then encode each pixel with GetRGB4 and the CLUT, as a 16 bit pixel array to send to the client
  1003.  
  1004.             P2CBuffer = malloc(iWidth * iHeight); // 1 byte per pixel : pen number
  1005.  
  1006.             // Allocate bitmap for temp. rastport for ReadPixelArray8()
  1007.             pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth,
  1008.                               BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap);    // Temp. BitMap for temp. RastPort
  1009.  
  1010.             // Initialize temporary rastport necessary for ReadPixelArray8()
  1011.             InitRastPort(&TempRP);
  1012.             TempRP.Layer = NULL;
  1013.             TempRP.BitMap = pBM;
  1014.             
  1015.             // Fill color lookup table with ready-to-send 16 bit RGB values
  1016.             jCnt = 1 << iDepth;
  1017.             for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1018.             {
  1019.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1020.                  ULONG wR = (lColor >> 8) & 0x0f;
  1021.                  ULONG wG = (lColor >> 4) & 0x0f;
  1022.                  ULONG wB = (lColor >> 0) & 0x0f;
  1023.                  CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1024.             }
  1025.                 
  1026.             // Read our chunky clut-index array from planar raster
  1027.             ReadPixelArray8(&(pActiveScreen -> RastPort),
  1028.                             (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1,
  1029.                             P2CBuffer,
  1030.                             &TempRP
  1031.                            );
  1032.  
  1033.             // Make up the RBG chunky buffer
  1034.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1035.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1036.                    *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[P2CBuffer[iCnt + jCnt * iWidth]];
  1037.         }
  1038. #ifndef PLANAR
  1039.         else if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky
  1040.         {
  1041.             // Fill color lookup table with 256 ready-to-send 16 bit RGB values
  1042.             for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1043.             {
  1044.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1045.                  ULONG wR = (lColor >> 8) & 0x0f;
  1046.                  ULONG wG = (lColor >> 4) & 0x0f;
  1047.                  ULONG wB = (lColor >> 0) & 0x0f;
  1048.                  CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1049.             }
  1050.  
  1051.             // Make up the RBG chunky buffer
  1052.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1053.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1054.                    *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[pRaster[iCnt + jCnt * iWidth]];
  1055.         }
  1056.         else // Picasso 96 2 byte pixel screen
  1057.         {
  1058.             // simply send raster memory (as 16 bit pixels)
  1059.             memcpy(pBuffer, pRaster, iSize);
  1060.         }
  1061. #endif        
  1062.         uSize = uLimit < iSize ? uLimit : iSize;
  1063.     }
  1064.     else // neither planar nor CLUT nor Pic96/2byte pixels (thus 3 or more byte pixels or CGFx > 1 Bpp), or VVA in any case
  1065.     {
  1066.         if (bPlanar)   // planar screen
  1067.         {
  1068.             // We have to :
  1069.             // - ReadPixelArray8 the whole screen,
  1070.             // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap
  1071.             // - Then encode each pixel with GetRGB4 and the CLUT, as a 8 bit BGR233 pixel array to send to the client
  1072.  
  1073.             P2CBuffer = malloc(iWidth * iHeight); // 1 byte per pixel : pen number
  1074.  
  1075.             // Allocate bitmap for temp. rastport for ReadPixelArray8()
  1076.             pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth,
  1077.                               BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap);    // Temp. BitMap for temp. RastPort
  1078.  
  1079.             // Initialize temporary rastport necessary for ReadPixelArray8()
  1080.             InitRastPort(&TempRP);
  1081.             TempRP.Layer = NULL;
  1082.             TempRP.BitMap = pBM;
  1083.             
  1084.             // Fill color lookup table with ready-to-send BGR233 values
  1085.             jCnt = 1 << iDepth;
  1086.             for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1087.             {
  1088.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1089.                  UBYTE wR = (lColor >> 9) & 0x07;
  1090.                  UBYTE wG = (lColor >> 5) & 0x07;
  1091.                  UBYTE wB = (lColor >> 2) & 0x03;
  1092.                  CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1093.             }
  1094.                 
  1095.             // Read our chunky clut-index array from planar raster
  1096.             ReadPixelArray8(&(pActiveScreen -> RastPort),
  1097.                             (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1,
  1098.                             P2CBuffer,
  1099.                             &TempRP
  1100.                            );
  1101.  
  1102.             // Make up the BGR233 chunky buffer
  1103.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1104.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1105.                    pBuffer[iCnt + jCnt * iWidth] = CLUT8[P2CBuffer[iCnt + jCnt * iWidth]];
  1106.             
  1107.             uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight;
  1108.         }
  1109. #ifndef PLANAR
  1110.         else if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky
  1111.         {
  1112.             // Fill color lookup table with 256 ready-to-send BGR233 values
  1113.             for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1114.             {
  1115.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1116.                  UBYTE wR = (lColor >> 9) & 0x07;
  1117.                  UBYTE wG = (lColor >> 5) & 0x07;
  1118.                  UBYTE wB = (lColor >> 2) & 0x03;
  1119.                  CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1120.             }
  1121.  
  1122.             // Make up the RBG chunky buffer
  1123.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1124.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1125.                    pBuffer[iCnt + jCnt * iWidth] = CLUT8[pRaster[iCnt + jCnt * iWidth]];
  1126.  
  1127.             uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight;
  1128.         }
  1129.         else // All RTG modes with depth > 1 byte
  1130.         {
  1131.             // We have to make 4 byte pixels out of the raster
  1132.             ReadPixelArray(pBuffer,     // Buffer
  1133.                    0, 0,        // Dest X/Y in buffer
  1134.                    iWidth * XDC_C_MAXDEPTH,     // Byte width of buffer
  1135.                    &(pActiveScreen -> RastPort),
  1136.                    0, 0,         // Source X/Y
  1137.                    iWidth, iHeight,  // Source w/h
  1138.                    RECTFMT_ARGB
  1139.                    );
  1140.                    
  1141.             if (bVVA)
  1142.             {
  1143.                 // Make up the BGR233 buffer
  1144.                 for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1145.                    for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1146.                 {
  1147.                     pBuffer[iCnt + jCnt * iWidth] =
  1148.                        (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 1] & 0xE0) >> 5 |
  1149.                        (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 2] & 0xE0) >> 2 |
  1150.                        (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 3] & 0xC0) >> 0;
  1151.                 }
  1152.                    
  1153.                 uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight;
  1154.             }
  1155.             else
  1156.                 uSize = uLimit < iWidth * iHeight * XDC_C_MAXDEPTH ? uLimit : iWidth * iHeight * XDC_C_MAXDEPTH;
  1157.         }
  1158. #endif
  1159.     }
  1160.  
  1161.     // Send buffer (by uLimit packet size if set).
  1162.     uCnt = 0;
  1163.     while (uCnt < (bVVA ? iWidth * iHeight : ((bFastMode) ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH)))
  1164.     {
  1165.         if (-1 == (send(iClientSocket, (UBYTE *) pBuffer + uCnt, uSize, 0)))
  1166.         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1167.      
  1168.         uCnt += uSize;
  1169.     }
  1170.  
  1171. #ifndef PLANAR
  1172.     // if CGFx or depth > 2, reallocate the buffer to actual raster size (eg .3 byte / pixel instead of 4)
  1173.     if (!bFastMode)
  1174.     {
  1175.         // Reallocate the buffer, resizing it to what's really necessary
  1176.         if (!(pBuffer = realloc(pBuffer, iWidth * iHeight * (CGXlib ? iDepth : ((iDepth != 3) ? iDepth : 4)))))
  1177.         { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; }
  1178.        
  1179.         // Byte copy the screen into the buffer for fast compare
  1180.         memcpy(pBuffer, pRaster, iSize);
  1181.     }
  1182. #endif
  1183.  
  1184.     // if planar, reallocate the buffer to iWidth x iDepth for ReadPixelArray8() and store chunky raster
  1185.     if (bPlanar)
  1186.     {
  1187.         // Reallocate the buffer, resizing it to what's really necessary
  1188.         if (!(pBuffer = realloc(pBuffer, iWidth * iHeight)))
  1189.         { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; }
  1190.        
  1191.         // Byte copy the screen into the buffer for fast compare
  1192.         memcpy(pBuffer, P2CBuffer, iWidth * iHeight);
  1193.         
  1194.         // Free P2CBuffer, which from now on is useless
  1195.         free(P2CBuffer);
  1196.         P2CBuffer = NULL;
  1197.     }
  1198.  
  1199. #ifndef PLANAR    
  1200.     // if RTG chunky CLUT, reallocate the buffer to iWidth x iDepth and copy screen raster into it
  1201.     if ((!bPlanar) && (iDepth == 1))
  1202.     {
  1203.         // Reallocate the buffer, resizing it to what's really necessary
  1204.         if (!(pBuffer = realloc(pBuffer, iWidth * iHeight)))
  1205.         { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; }
  1206.        
  1207.         // Byte copy the screen into the buffer for fast compare
  1208.         memcpy(pBuffer, pRaster, iWidth * iHeight);
  1209.     }
  1210. #endif
  1211.     
  1212.     // Preset framebuffer update message X and Y size to XDC_TILE
  1213.     mFBRMsg.r.w =
  1214.     mFBRMsg.r.h = XDC_TILE;
  1215.  
  1216.     // Release a key to the client socket so that child process can grab it
  1217.     if (-1 == (iDuplicateSocketKey = ReleaseCopyOfSocket(iClientSocket, UNIQUE_ID)))
  1218.     { vCleanSession("main.c / main : ReleaseCopyOfSocket() error", Errno()); goto _NewSession; }
  1219.  
  1220.     // Create incoming messages handling child process
  1221.     if (!CreateNewProcTags(
  1222.           NP_Entry, vProcessIncomes,
  1223.           NP_StackSize, 32000,
  1224.           NP_Name, "AmiVNC handler",
  1225.           TAG_DONE
  1226.        ))
  1227.     { vCleanSession("main.c / main : CreateNewProcTags() error", 0); goto _NewSession; }
  1228.         
  1229.     // Execute user command on accepted connection (if any)
  1230.     if (pPreStart)
  1231.     {
  1232.         char cCommand[128];
  1233.         sprintf(cCommand, pPreStart, inet_ntoa(cliAddr.sin_addr));
  1234.         SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE);
  1235.     }
  1236.     
  1237.     // Session is truly opened now
  1238.     bSession = TRUE;
  1239.     
  1240.     // While not end of session (by child or by ourself)
  1241.     while (!bDie)
  1242.     {
  1243.     // Search for active screen change
  1244.     if (IntuitionBase -> FirstScreen != pActiveScreen)
  1245.     {
  1246.         if (bPlanar) // Original Amiga screens
  1247.         {
  1248.             // Check if new screen is also planar and has same dimensions
  1249.             if ((GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD)
  1250.              && (iWidth == GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_WIDTH)) // X size
  1251.              && (iHeight == GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_HEIGHT))) // Y size
  1252.             {
  1253.                 // Grab new screen
  1254.                 pActiveScreen = IntuitionBase -> FirstScreen;
  1255.                 fprintf(fLog, "main.c / main : Screen set to [%s]\n", pActiveScreen -> Title);
  1256.                     
  1257.                 // Update depth
  1258.                 iDepth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel
  1259.                     
  1260.                 // Update CLUT (or CLUT8 if bVVA)
  1261.                 jCnt = 1 << iDepth;
  1262.                 if (bVVA) // BGR233
  1263.                     for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1264.                     {
  1265.                          ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1266.                          UBYTE wR = (lColor >> 9) & 0x07;
  1267.                          UBYTE wG = (lColor >> 5) & 0x07;
  1268.                          UBYTE wB = (lColor >> 2) & 0x03;
  1269.                          CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1270.                     }
  1271.                 else      // RGB16PC
  1272.                     for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1273.                     {
  1274.                          ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1275.                          ULONG wR = (lColor >> 8) & 0x0f;
  1276.                          ULONG wG = (lColor >> 4) & 0x0f;
  1277.                          ULONG wB = (lColor >> 0) & 0x0f;
  1278.                          CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1279.                     }
  1280.                 
  1281.                 // Force client screen update (almost :-)
  1282.                 memset(pBuffer, iWidth * iHeight, 0xFF);
  1283.             }
  1284.             else
  1285.             { vCleanSession("main.c / main : planar screenmode switch not allowed", 0); goto _NewSession; }
  1286.         }
  1287. #ifndef PLANAR
  1288.         else // Chunky (RTG)
  1289.         {
  1290.             if (GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  1291.              && GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM)
  1292.              && iWidth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_WIDTH)
  1293.              && iHeight == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT)
  1294.              && iDepth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_BPPIX))
  1295.             {
  1296.                 // Grab new screen
  1297.                 pActiveScreen = IntuitionBase -> FirstScreen;
  1298.                 fprintf(fLog, "main.c / main : Screen set to [%s]\n", pActiveScreen -> Title);
  1299.                 UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  1300.                      LBMI_BASEADDRESS, (ULONG *) &uCnt,
  1301.                      TAG_DONE));
  1302.                 pRaster = (UBYTE *) uCnt;
  1303.                 
  1304.                 // If depth == 1, update CLUT
  1305.                 if (iDepth == 1)
  1306.                 {
  1307.                     if (bVVA) // BGR233
  1308.                         for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1309.                         {
  1310.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1311.                              UBYTE wR = (lColor >> 9) & 0x07;
  1312.                              UBYTE wG = (lColor >> 5) & 0x07;
  1313.                              UBYTE wB = (lColor >> 2) & 0x03;
  1314.                              CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1315.                         }
  1316.                     else      // RGB16PC
  1317.                         for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1318.                         {
  1319.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1320.                              ULONG wR = (lColor >> 8) & 0x0f;
  1321.                              ULONG wG = (lColor >> 4) & 0x0f;
  1322.                              ULONG wB = (lColor >> 0) & 0x0f;
  1323.                              CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1324.                         }
  1325.                 
  1326.                     // Force client screen update (almost :-)
  1327.                     memset(pBuffer, iWidth * iHeight, 0xFF);
  1328.                 }
  1329.             }
  1330.             else
  1331.             { vCleanSession("main.c / main : chunky screenmode switch not allowed", 0); goto _NewSession; }
  1332.         }
  1333. #endif
  1334.     }
  1335.                 
  1336.     // Search for changes in screen...
  1337.     for (jCnt = 0 ; jCnt < iHeight; jCnt += XDC_TILE)
  1338.     {
  1339.         for (iCnt = 0 ; iCnt < iWidth ; iCnt += XDC_TILE)
  1340.         {
  1341.             register int iYtile, iXtile;
  1342.             BOOL bChange = FALSE;
  1343. #ifndef PLANAR    
  1344.             if (!bPlanar) // chunky linear-addressed rasters
  1345.                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1346.                 {
  1347.                     if (memcmp((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1348.                        (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1349.                        XDC_TILE * iDepth))
  1350.                     {
  1351.                         memcpy((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1352.                            (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1353.                            XDC_TILE * iDepth);
  1354.  
  1355.                         bChange = TRUE;
  1356.                     }
  1357.                 }
  1358.             else // planar rasters
  1359.             {
  1360. #endif
  1361.                 // 0 - Once every 10 scans, refresh palette (we have no event here to say palette has changed)
  1362.                 if (!(iUpdate++ % 10))
  1363.                 {
  1364.                     int nColor = 1 << iDepth, iColor;
  1365.                     if (bVVA)
  1366.                         for (iColor = 0 ; iColor < 256 ; iColor++)
  1367.                         {
  1368.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1369.                              UBYTE wR = (lColor >> 9) & 0x07;
  1370.                              UBYTE wG = (lColor >> 5) & 0x07;
  1371.                              UBYTE wB = (lColor >> 2) & 0x03;
  1372.                              CLUT8[iColor] = (wB << 3 | wG) << 3 | wR;
  1373.                         }
  1374.                     else
  1375.                         for (iColor = 0 ; iColor < nColor ; iColor++)
  1376.                         {
  1377.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1378.                              ULONG wR = (lColor >> 8) & 0x0f;
  1379.                              ULONG wG = (lColor >> 4) & 0x0f;
  1380.                              ULONG wB = (lColor >> 0) & 0x0f;
  1381.                              CLUT[iColor] = (wG << 4 | wB) << 8 | wR;
  1382.                         }
  1383.                 }
  1384.                 
  1385.                 // 1 - get a chunky 32x32 1 byte clut entry buffer
  1386.                 ReadPixelArray8(&(pActiveScreen -> RastPort),
  1387.                                 (unsigned long) iCnt, (unsigned long) jCnt, (unsigned long) iCnt + XDC_TILE - 1, (unsigned long) jCnt + XDC_TILE - 1,
  1388.                                 uCTile,
  1389.                                 &TempRP
  1390.                                );
  1391.                                
  1392.                 // 2 - then compare it to reference buffer. if !=, remember to update client and store new.
  1393.                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1394.                 {
  1395.                     if (memcmp((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth),
  1396.                                (UBYTE *) (uCTile) + (iYtile * XDC_TILE),
  1397.                                XDC_TILE))
  1398.                     {
  1399.                         memcpy((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth),
  1400.                                (UBYTE *) (uCTile) + (iYtile * XDC_TILE),
  1401.                                XDC_TILE);
  1402.                                
  1403.                         bChange = TRUE;
  1404.                     }
  1405.                 }
  1406. #ifndef PLANAR
  1407.             }
  1408. #endif
  1409.         
  1410.         // If change found, send the tile
  1411.         if (bChange)
  1412.         {
  1413.             if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  1414.             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1415.  
  1416.             mFBRMsg.r.x = iCnt;
  1417.             mFBRMsg.r.y = jCnt;
  1418.        
  1419.             // Send framebuffer update header
  1420.             if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  1421.             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1422.  
  1423.             // Send update data
  1424.             if (bPlanar)
  1425.             {
  1426.                 if (bVVA)
  1427.                 {
  1428.                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1429.                        for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++)
  1430.                            uTile[iXtile + iYtile * XDC_TILE] = CLUT8[uCTile[iXtile + iYtile * XDC_TILE]];
  1431.                 
  1432.                     // Send framebuffer update pixel data
  1433.                     if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1434.                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1435.                 }
  1436.                 else
  1437.                 {
  1438.                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1439.                        for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++)
  1440.                            *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[uCTile[iXtile + iYtile * XDC_TILE]];
  1441.                 
  1442.                     // Send framebuffer update pixel data
  1443.                     if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1444.                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1445.                 }
  1446.             }
  1447. #ifndef PLANAR
  1448.             else if ((!bVVA) && (bFastMode) && (iDepth == 2)) // 2 byte pixels under Pic96 : send directly from buffer (2 is idepth)
  1449.             {
  1450.                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1451.                    memcpy(uTile + XDC_TILE * iYtile * iDepth,
  1452.                           pRaster + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1453.                           XDC_TILE * iDepth);
  1454.             
  1455.                 // Send framebuffer update pixel data
  1456.                 if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1457.                 { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1458.             }
  1459.             else if ((!bVVA) && (iDepth == 1)) // RTG chunky 1 byte pixels
  1460.             {
  1461.                 // Every 10 update, refresh color lookup table with 256 ready-to-send 16 bit RGB values
  1462.                 if (!(iUpdate++ % 10))
  1463.                 {
  1464.                     int iColor;
  1465.                     for (iColor = 0 ; iColor < 256 ; iColor++)
  1466.                     {
  1467.                          ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1468.                          ULONG wR = (lColor >> 8) & 0x0f;
  1469.                          ULONG wG = (lColor >> 4) & 0x0f;
  1470.                          ULONG wB = (lColor >> 0) & 0x0f;
  1471.                          CLUT[iColor] = (wG << 4 | wB) << 8 | wR;
  1472.                     }
  1473.                 }
  1474.  
  1475.                 // Make up the RBG chunky buffer
  1476.                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1477.                    for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1478.                        *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]];
  1479.             
  1480.                 // Send framebuffer update pixel data
  1481.                 if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1482.                 { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1483.  
  1484.             }
  1485.             else // Dumb screenmode or VVA
  1486.             {
  1487.                 if (iDepth > 1)
  1488.                 {
  1489.                     ReadPixelArray(uTile,     // Buffer
  1490.                                0, 0,        // Dest X/Y in buffer
  1491.                                XDC_TILE * XDC_C_MAXDEPTH,
  1492.                                &(pActiveScreen -> RastPort),
  1493.                                iCnt, jCnt,         // Source X/Y
  1494.                                XDC_TILE, XDC_TILE,  // Source w/h
  1495.                                RECTFMT_ARGB
  1496.                                );
  1497.                         
  1498.                     if (bVVA)
  1499.                     {
  1500.                         // Make the BGR233 buffer into uTile
  1501.                         for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1502.                            for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1503.                         {
  1504.                             uTile[iXtile + iYtile * XDC_TILE] =
  1505.                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 1] & 0xE0) >> 5 |
  1506.                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 2] & 0xE0) >> 2 |
  1507.                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 3] & 0xC0) >> 0;
  1508.                         }
  1509.                 
  1510.                         // Send framebuffer update pixel data
  1511.                         if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1512.                         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1513.                     }
  1514.                     else
  1515.                     {
  1516.                         // Send framebuffer update pixel data
  1517.                         if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH, 0)))
  1518.                         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1519.                     }
  1520.                 }
  1521.                 else // iDepth == 1 and VVA (Depth == 1 and not VVA is trated above)
  1522.                 {
  1523.                     // Once every 10 scans, refresh palette (we have no event here to say palette has changed)
  1524.                     if (!(iUpdate++ % 10))
  1525.                     {
  1526.                         int iColor;
  1527.                             for (iColor = 0 ; iColor < 256 ; iColor++)
  1528.                             {
  1529.                                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1530.                                  UBYTE wR = (lColor >> 9) & 0x07;
  1531.                                  UBYTE wG = (lColor >> 5) & 0x07;
  1532.                                  UBYTE wB = (lColor >> 2) & 0x03;
  1533.                                  CLUT8[iColor] = (wB << 3 | wG) << 3 | wR;
  1534.                             }
  1535.                     }
  1536.                     
  1537.                     // Make up the RBG chunky buffer
  1538.                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1539.                        for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1540.                            uTile[iXtile + iYtile * XDC_TILE] = CLUT8[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]];
  1541.             
  1542.                     // Send framebuffer update pixel data
  1543.                     if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1544.                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1545.                 }
  1546.             }
  1547. #endif
  1548.         }
  1549.         }
  1550.     }
  1551.     }
  1552.     
  1553.     vCleanSession("main.c / main : Session stop (child stopped)", 0);
  1554.     goto _NewSession;
  1555. }
  1556.